using Sirenix.OdinInspector;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Timeline;

#region SkillBase
public abstract class VActSkillBase
{
    [TableList(AlwaysExpanded = true)]
    public List<VActSkillUnit> skills=new List<VActSkillUnit>();
    protected VActProcessor processor;
    protected VActInput input;
    public void InitLoader(VActProcessor vActProcessor, VActInput vActInput)
    {
        processor = vActProcessor;
        input = vActInput;
        Load();

        processor.onEnterNewAct += ReleaseActSkill;
    }
    public abstract void Load();

    //这个地方目前先做成最简单的单轴,后面肯定要升级的,而且还是Timeline播放中的管理器
    //用来传递资源和各种信息
    //这个地方的标识必须分配同一标识位子,用来用头cancle全部
    public Observer ExtenseAssetToObserver(string SkillName, TimelineAsset timelineAsset)
    {
        if (timelineAsset == null) return null;
        //老代码用的是边播边展开, 但是可以直接展开
        List<Observer> obs = new List<Observer>();
        var clips = GetClip(timelineAsset);
        //创建技能头
        var SkillHead = new TriggerObserver()
        {
            name = SkillName,
            start = () => PlayingClip = clips.Count
        };
        SkillHead.BuildChain();


        for (int i = 0; i < clips.Count; i++)
        {
            var tc = clips[i];
            var vc = tc.ToClip();
            var vb = tc.ToBehavior();
            var graph = processor.GetGraph(vb.clipType);
            float duration = (float)tc.duration;

            if (vc.dirveByFunc)
            {
                //更加完善的写法
                var clipStart = new TObserver()
                {
                    name = $"{processor.gameObject.name}_{timelineAsset.name}:{tc.displayName}",
                    duration = (float)tc.start
                };
                var clipBody = new FuncObserver()
                {
                    start = () => graph.Play(tc), //tc实际是被包装为ScriptPlayable放到Graph中自驱动了, 所以后面只需要关闭就行
                    complete = graph.Complete
                };
                clipBody.end = () =>
                {
                    CompleteClip();
                    graph.EndLast();
                };
                //这里可能得创建一个bool checker ,但是目前可以先省略
                clipStart.Next(clipBody); //头尾相关的clip会自动关联到一条链上
                obs.Add(clipStart);
            }
            else
            {
                var clipStart = new TObserver()
                {
                    name = $"{processor.gameObject.name}_{timelineAsset.name}:{tc.displayName}",
                    duration = (float)tc.start
                };
                var clipBody = new TObserver()
                {
                    start = () => graph.Play(tc), //tc实际是被包装为ScriptPlayable放到Graph中自驱动了, 所以后面只需要关闭就行
                    duration = duration
                };
                clipBody.end = () =>
                {
                    CompleteClip();
                    graph.EndLast();
                };
                clipStart.Next(clipBody);
                obs.Add(clipStart);
            }
        }

        //就是说所有通过play用到的clip资源都要手动记录并释放, 并且observer需要被打断
        //在这个过程中, observer链条需要被记录, timelineclip.asset需要被记录,这个是每条关联observer的,粗暴一点直接observer关联资源地址


        foreach (var ob in obs)
        {
            ob.Wait(SkillHead);
        }

        return SkillHead;

    }
    private int _playingClip;
    private int PlayingClip
    {
        get => _playingClip;
        set
        {
            if (value == -1) return;
            if (value == 0)
            {
                CompleteSkill();
                _playingClip = 0;
                return;
            }
            _playingClip = value;
        }
    }


    public Action onSkillComplete;
    private void CompleteClip() => PlayingClip--;
    private void CompleteSkill()
    {
        onSkillComplete?.Invoke();
        processor.ContinueState();
        onSkillComplete = null;
    }
    public void ReleaseActSkill(VAct act)
    {
        if (_playingClip == 0)
        {
            //什么也不做,资源已经释放完了
        }
        else
        {
            //解放状态,释放上一个资源
            _playingClip = 0;
            input.doingAct?.actObserver.SelfCancle();
            input.doingAct?.actObserver.DismissChain();
        }
    }
    public List<TimelineClip> GetClip(TimelineAsset timelineAsset)
    {
        var collection = new List<TimelineClip>(50);
        foreach (var track in timelineAsset.GetRootTracks())
        {
            if (!track.muted)
            {
                collection.AddRange(track.GetClips());
            }
        }
        return collection;
    }
    public TimelineAsset NameTo(string name) => skills.Find(x => x.name == name)?.asset;
}
[Serializable]
public class VActSkillUnit
{
    public string name;
    public TimelineAsset asset;
}
#endregion
public class VActSkillBaseOverride : VActSkillBase
{
    public override void Load()
    {
        //var Atk = ExtenseAssetToObserver("Atk", NameTo("Atk"));
        //input.AddAct("Atk", Atk, 1, 100);

        //var Atk2 = ExtenseAssetToObserver("Atk2", NameTo("Atk2"));
        //input.AddAct("Atk2", Atk2, 1, 110);

        foreach (var item in skills)
        {
            var skill = ExtenseAssetToObserver(item.name,item.asset);
            input.AddAct(item.name, skill, 1, 100);
        }
    }
}
